{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "db68f9ed-b3d6-4722-92da-d23681ceaab2",
   "metadata": {},
   "source": [
    "# Exercise 1\n",
    "\n",
    "## Supervised Learning- Regression Models\n",
    "\n",
    "\n",
    "---\n",
    "\n",
    "## Overview\n",
    "\n",
    "Welcome to this excercise. We are now going to use our new skills to build our supervised learning models that use a regression approach.\n",
    "\n",
    "---\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "15eef706",
   "metadata": {},
   "outputs": [],
   "source": [
    "!pip install statsmodels"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "cd4b8b09-f9e0-4c1f-9885-1aef53e84bef",
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "import os\n",
    "\n",
    "# Manually set the path relative to the py file's location that you want to import\n",
    "func_lib_path = os.path.abspath(os.path.join(os.getcwd(), '../../'))# Add the path to sys.path\n",
    "sys.path.append(func_lib_path)\n",
    "\n",
    "# Now you can import func_lib\n",
    "import func_lib\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "import statsmodels.api as sm\n",
    "from sklearn.linear_model import LinearRegression"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "c82294fa-8583-43e2-9f50-be891efdef8c",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[*********************100%%**********************]  501 of 501 completed\n",
      "\n",
      "1 Failed download:\n",
      "['SW']: YFChartError(\"%ticker%: Data doesn't exist for startDate = 946702800, endDate = 1714536000\")\n"
     ]
    }
   ],
   "source": [
    "# Retrieve historical price data.\n",
    "# - Use the 'createHistPrices()' function from 'func_lib' to get historical price data.\n",
    "# - Assign the result to the variable 'historical_prices'.\n",
    "\n",
    "historical_prices = func_lib.create_hist_prices()\n",
    "\n",
    "# Define the list of momentum periods.\n",
    "# - Create a list containing different time periods for calculating momentum indicators.\n",
    "# - Assign this list to the variable 'list_of_momentums'.\n",
    "\n",
    "list_of_momentums = [1, 5, 15, 20]\n",
    "\n",
    "# Compute returns based on historical prices and momentum periods.\n",
    "# - Use the 'computingReturns()' function from 'func_lib' with 'historical_prices' and 'list_of_momentums' as inputs.\n",
    "# - Assign the result to the variable 'total_returns'.\n",
    "\n",
    "total_returns = func_lib.compute_returns(historical_prices, list_of_momentums)\n",
    "\n",
    "# Remove any rows with missing values from the returns data.\n",
    "# - Use the 'dropna()' method to remove rows with NaN values from 'total_returns'.\n",
    "# - Apply the change in place to modify the DataFrame directly.\n",
    "\n",
    "total_returns.dropna(inplace=True)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "5967d6de-5270-4a3e-969e-7a3fbcce2d62",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2017-01-20 00:00:00')"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Determine the split index for 70% of the dates.\n",
    "# - Extract the unique dates from the index of 'total_returns'.\n",
    "# - Calculate the split date by indexing into the unique dates to get the date corresponding to 70% of the total length of unique dates.\n",
    "# - Assign this date to the variable 'split_date' and display it.\n",
    "\n",
    "unique_dates = total_returns.index.get_level_values('Date').unique()\n",
    "split_date = unique_dates[int(0.7 * len(unique_dates))]\n",
    "print(split_date)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "c02c2d11-1505-4bb5-8bd8-3b3e6698f1f0",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create the training set: all data before the split date.\n",
    "# - Use the 'loc[]' indexer to select rows from 'total_returns' where the date in the index is earlier than 'split_date'.\n",
    "# - Assign this subset of data to the variable 'train_data'.\n",
    "\n",
    "\n",
    "\n",
    "# Create the testing set: all data from the split date onwards.\n",
    "# - Use the 'loc[]' indexer to select rows from 'total_returns' where the date in the index is equal to or later than 'split_date'.\n",
    "# - Assign this subset of data to the variable 'test_data'.\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "2f42ac29-0062-4894-a158-2173eb917714",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Extract the target variable for testing.\n",
    "# - Select the 'F_1_d_returns' column from the 'test_data' DataFrame.\n",
    "# - Assign this column to the variable 'total_returns'.\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "ee5782b5-3c6e-41da-a17d-b52f01a4359d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define the feature and target columns.\n",
    "# - List the names of the feature columns in 'features'.\n",
    "# - List the name of the target column in 'target'.\n",
    "\n",
    "\n",
    "\n",
    "# Split the data into training and testing sets.\n",
    "# - Extract the feature columns from 'train_data' and 'test_data' to create 'X_train' and 'X_test'.\n",
    "# - Extract the target column from 'train_data' and 'test_data' to create 'y_train' and 'y_test'.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "ed9e2980-0253-4b63-92f3-751918ccd4e1",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Standardize the features.\n",
    "# - Create an instance of 'StandardScaler' for scaling the features.\n",
    "# - Fit the scaler to the training data and transform both the training and testing feature sets.\n",
    "# - Convert the scaled arrays back to DataFrames with the same index and column names as the original feature sets.\n",
    "\n",
    "\n",
    "# Scale the training features\n",
    "\n",
    "# Scale the testing features\n",
    "\n",
    "\n",
    "# Convert the scaled arrays back to DataFrames\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "d1d6724a-1094-4ae9-8e9b-b032676cbae9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                            OLS Regression Results                            \n",
      "==============================================================================\n",
      "Dep. Variable:          F_1_d_returns   R-squared:                       0.002\n",
      "Model:                            OLS   Adj. R-squared:                  0.002\n",
      "Method:                 Least Squares   F-statistic:                     678.3\n",
      "Date:                Sun, 01 Sep 2024   Prob (F-statistic):               0.00\n",
      "Time:                        23:55:47   Log-Likelihood:             4.1267e+06\n",
      "No. Observations:             1795319   AIC:                        -8.253e+06\n",
      "Df Residuals:                 1795314   BIC:                        -8.253e+06\n",
      "Df Model:                           4                                         \n",
      "Covariance Type:            nonrobust                                         \n",
      "================================================================================\n",
      "                   coef    std err          t      P>|t|      [0.025      0.975]\n",
      "--------------------------------------------------------------------------------\n",
      "const            0.0007   1.81e-05     40.134      0.000       0.001       0.001\n",
      "1_d_returns     -0.0001   2.01e-05     -7.107      0.000      -0.000      -0.000\n",
      "5_d_returns     -0.0007   2.33e-05    -30.288      0.000      -0.001      -0.001\n",
      "15_d_returns    -0.0005   3.54e-05    -14.102      0.000      -0.001      -0.000\n",
      "20_d_returns     0.0003   3.35e-05      9.162      0.000       0.000       0.000\n",
      "==============================================================================\n",
      "Omnibus:                   616143.185   Durbin-Watson:                   2.000\n",
      "Prob(Omnibus):                  0.000   Jarque-Bera (JB):         71582377.022\n",
      "Skew:                           0.642   Prob(JB):                         0.00\n",
      "Kurtosis:                      33.907   Cond. No.                         3.98\n",
      "==============================================================================\n",
      "\n",
      "Notes:\n",
      "[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.\n"
     ]
    }
   ],
   "source": [
    "# Add a constant to the model (intercept).\n",
    "# - Use 'sm.add_constant()' to add a column of ones to the scaled feature sets for both training and testing data.\n",
    "# - This column represents the intercept term in the regression model.\n",
    "\n",
    "X_train_scaled_const_add = sm.add_constant(X_train_scaled)\n",
    "X_test_scaled_const_add  = sm.add_constant(X_test_scaled)\n",
    "\n",
    "# Fit the model.\n",
    "# - Create an Ordinary Least Squares (OLS) regression model using 'sm.OLS()' with the scaled training features and the target variable.\n",
    "# - Fit the model to the training data.\n",
    "\n",
    "model = sm.OLS(y_train, X_train_scaled_const_add).fit()\n",
    "\n",
    "# Print the model summary.\n",
    "# - Use 'model.summary()' to output the regression results, including coefficients, R-squared, and other statistical metrics.\n",
    "\n",
    "print(model.summary())\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "7f39393e-1f82-41df-b657-c5f262bcf0cd",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Set the model name.\n",
    "# - Assign the name 'Reg' to the variable 'model_name' to label the regression model.\n",
    "\n",
    "\n",
    "# Make predictions using the fitted model.\n",
    "# - Use 'model.predict()' to generate predictions based on the scaled testing features with the added constant.\n",
    "\n",
    "# - Convert the true target values 'y_test' and predicted values 'y_pred' to DataFrames.\n",
    "# - Rename the column in 'y_pred_df' to match the model name.\n",
    "\n",
    "y_test_df = pd.DataFrame(y_test)\n",
    "y_pred_df = pd.DataFrame(y_pred)\n",
    "y_pred_df.rename(columns={0: model_name}, inplace=True)\n",
    "\n",
    "# Combine the actual and predicted values into one DataFrame.\n",
    "# - Use 'pd.merge()' to merge 'y_pred_df' with 'total_returns' on their index.\n",
    "# - This combines the predicted values with the actual returns data.\n",
    "\n",
    "y_test_and_pred = pd.merge(y_pred_df, total_returns, left_index=True, right_index=True)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "82f6ecce-d8d6-41da-acb5-afd6dc10bbc8",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define a trading strategy based on logistic regression predictions.\n",
    "# - Create a function 'trading_strategy' that takes the predicted value 'y_pred' as input.\n",
    "# - If the predicted value is greater than 0, return 1 (indicating a \"Go long\" signal).\n",
    "# - Otherwise, return 0 (indicating no action or \"Do nothing\").\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "83243879-11f9-4e4c-abce-24f662fc0c37",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 50736 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The CAGR is: 16.05%\n",
      "Sharpe Ratio of Strategy: 0.85\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 15516 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Compute performance metrics based on the predictions and actual returns.\n",
    "# - Use the 'func_lib.compute_BM_Perf()' function to calculate cumulative and calendar returns.\n",
    "# - Pass the DataFrame 'y_test_and_pred' containing the actual and predicted values as an argument.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "a446adf2-bbf2-486c-9c63-0a26239aa26a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 63464 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The CAGR is: 14.96%\n",
      "Sharpe Ratio of Strategy: 0.88\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 17692 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Compute strategy performance metrics.\n",
    "# - Use the 'func_lib.compute_strat_perf()' function to calculate the performance of the trading strategy.\n",
    "# - Pass the following arguments:\n",
    "#   - 'y_test_and_pred': The DataFrame containing actual and predicted values.\n",
    "#   - 'cum_returns': Cumulative returns calculated previously.\n",
    "#   - 'calendar_returns': Calendar returns calculated previously.\n",
    "#   - 'trading_strategy': The function defining the trading strategy based on predictions.\n",
    "#   - 'model_name': The name of the model to include in the performance evaluation.\n",
    "\n",
    "\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
